package cn.itcast.es;

import cn.itcast.es.pojo.Goods;
import cn.itcast.es.utils.ElasticUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 虎哥
 */
@Slf4j
public class ElasticsearchBasicDemo {

    public static final String SOURCE = "{\n" +
            "  \"settings\": {\n" +
            "    \"number_of_shards\": 3,\n" +
            "    \"number_of_replicas\": 1, \n" +
            "    \"analysis\": {\n" +
            "      \"analyzer\": {\n" +
            "        \"my_pinyin\": {\n" +
            "          \"tokenizer\": \"ik_max_word\",\n" +
            "          \"filter\": [\n" +
            "            \"py\"\n" +
            "          ]\n" +
            "        }\n" +
            "      },\n" +
            "      \"filter\": {\n" +
            "        \"py\": {\n" +
            "          \"type\": \"pinyin\",\n" +
            "          \"keep_full_pinyin\": false,\n" +
            "          \"keep_joined_full_pinyin\": true,\n" +
            "          \"keep_original\": true,\n" +
            "          \"limit_first_letter_length\": 16,\n" +
            "          \"none_chinese_pinyin_tokenize\": false\n" +
            "        }\n" +
            "      }\n" +
            "    }\n" +
            "  },\n" +
            "  \"mappings\": {\n" +
            "    \"properties\": {\n" +
            "      \"id\": {\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"name\": {\n" +
            "        \"type\": \"completion\",\n" +
            "        \"analyzer\": \"my_pinyin\",\n" +
            "        \"search_analyzer\": \"ik_max_word\"\n" +
            "      },\n" +
            "      \"title\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"my_pinyin\",\n" +
            "        \"search_analyzer\": \"ik_max_word\"\n" +
            "      },\n" +
            "      \"price\":{\n" +
            "        \"type\": \"long\"\n" +
            "      }\n" +
            "    }\n" +
            "  }\n" +
            "}";

    private ElasticUtils<Goods> elasticUtil;

    @Test
    public void testCreateIndex() throws IOException {
        elasticUtil.createIndex(SOURCE);
    }

    @Test
    public void testDeleteIndex() throws IOException {
        elasticUtil.deleteIndex();
    }

    @Test
    public void testAddDocument() throws IOException {
        // 一个文档
        Goods goods = new Goods(1L, Arrays.asList("红米9", "手机"), "红米9手机 数码", 1499L);

        elasticUtil.addGoods(goods, goods.getId());
    }

    @Test
    public void testBulk() throws IOException {
        // 1.准备文档数据
        List<Goods> list = new ArrayList<>();
        list.add(new Goods(1L, Arrays.asList("红米9", "手机"), "红米9手机 数码", 1499L));
        list.add(new Goods(2L, Arrays.asList("三星", "Galaxy", "手机"), "三星 Galaxy A90 手机 数码 疾速5G 骁龙855", 3099L));
        list.add(new Goods(3L, Arrays.asList("Sony", "WH-1000XM3"), "Sony WH-1000XM3 降噪耳机 数码", 2299L));
        list.add(new Goods(4L, Arrays.asList("松下", "剃须刀"), "松下电动剃须刀高转速磁悬浮马达", 599L));
        list.add(new Goods(5L, Arrays.asList("索尼", "剃须刀"), "索尼电动剃须刀高转速磁悬浮马达", 699L));

        for (Goods goods : list) {
            elasticUtil.addGoods(goods, goods.getId());
        }
    }

    @Test
    public void testDeleteDocument() throws IOException {
        elasticUtil.deleteById(1L);
    }

    @Test
    public void testGetDocument() throws IOException, InterruptedException {
        System.out.println("开始查询");
        Mono<Goods> mono = elasticUtil.getById(1L, Goods.class);
        System.out.println("结束查询");
        mono.subscribe(System.out::println);

        Thread.sleep(2000);
    }

    @Test
    public void testSearch() throws IOException, InterruptedException {

        // 2.给Request对象准备请求参数
        // 2.1.创建SourceBuilder
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 2.2.query条件
        // 2.2.1.构建布尔查询
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 2.2.2.添加must
        queryBuilder.must(QueryBuilders.matchQuery("title", "手机"));
        // 2.2.3.添加filter
        queryBuilder.filter(QueryBuilders.rangeQuery("price").gt(100).lt(10000));
        sourceBuilder.query(queryBuilder);
        // 2.3.分页条件
        sourceBuilder.from(0).size(5);
        // 2.4.排序
        sourceBuilder.sort("price", SortOrder.ASC);
        // 2.5.高亮
        sourceBuilder.highlighter(new HighlightBuilder().field("title"));
        // 2.6.source过滤
        sourceBuilder.fetchSource(new String[]{"id", "title", "price"}, null);

        // 查询
        log.warn("开始查询");
        Flux<Goods> flux = elasticUtil.search(sourceBuilder, Goods.class);
        log.warn("结束查询");

        flux.subscribe(System.out::println);

        Thread.sleep(2000);
    }

    @Test
    public void testSuggest() throws IOException {
        List<String> list = elasticUtil.suggest("s", "name");

        for (String s : list) {
            System.out.println("s = " + s);
        }
    }

    @Before
    public void beforeClass() {
        RestHighLevelClient highLevelClient = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://ly-es:9200")
        ));
        this.elasticUtil = new ElasticUtils<Goods>(highLevelClient, "goods");
    }

    @After
    public void afterClass() throws IOException {
        this.elasticUtil.close();
    }
}
